<?php
/**
 * 路由处理
 * @copyright 2020-2021 WillPHP
 * @author NoMind<24203741@qq.com/113344.com>
 * @version WillPHPv3
 * @since 2021-12-16
 */
namespace wiphp;
defined('WIPHP_URI') or die('Access Denied');
class Route {
	protected static $filter = '/[^a-zA-Z0-9\x7f-\xff\.\/\-_]+/i'; 
	protected static $types = [
			':num' => '[0-9\-]+',
			':float' => '[0-9\.\-]+',
			':string' => '[a-zA-Z0-9\-_]+',
			':alpha' => '[a-zA-Z\x7f-\xff0-9-_]+',
			':any' => '.*',
			':page' => '[0-9|_PAGE_]+', 
	];
	protected static $def_controller = 'index';
	protected static $def_method = 'index';
	protected static $rule = [];
	protected static $ruleFlip = [];
	//处理路由
	public static function parseRoute() {
		self::init();
		$path = self::parseUrl();
		$analysis = [];
		$analysis['status'] = 404;
		$analysis['rule'] = $path;
		if (isset(self::$rule[$path])) {
			$analysis['status'] = 200;
			$analysis['route'] = self::$rule[$path];
		} elseif (!empty(self::$rule)) {	
			foreach (self::$rule as $k => $v) {
				if (preg_match('#^'.$k.'$#i', $path, $matches)) {
					if (strpos($v, '$') !== false && strpos($k, '(') !== false) {
						$v = preg_replace('#^'.$k.'$#i', $v, $path);
					}
					$analysis['status'] = 200;
					$analysis['route'] = $v;
					break;
				}
			}
		}
		if (!isset($analysis['route'])) {
			if (empty($path)) {
				$analysis['rule'] = $analysis['route'] = self::$def_controller.'/'.self::$def_method;
			} else {
				$path_list = explode('/', $path);
				$controller = !empty($path_list[0])? $path_list[0] : self::$def_controller;
				$action = isset($path_list[1])? $path_list[1] : self::$def_method;
				$analysis['rule'] = $controller.'/'. $action;
				$analysis['route'] = (count($path_list)>=2)? $path : $path.'/'.self::$def_method;
			}
		}
		if (isset($analysis['route'])) {
			$param = [];
			$route_list = explode('/', $analysis['route']);
			for($i = 2; $i < count($route_list); $i += 2) {
				if (isset($route_list[$i + 1])) {
					$param[$route_list[$i]] = $route_list[$i + 1];
				}
			}
			$analysis['param'] = self::getParams($param);
			$analysis['param']['req'] = $analysis['param'];
		}
		$route = explode('/', $analysis['route']);		
		define('__MODULE__', ucfirst($route[0]));
		define('__ACTION__', $route[1]);	
		return $analysis;		
	}	
	protected static function getParams($param = []) {
		return array_merge($param, $_GET, $_POST);
	}
	protected static function init() {
		$config = Config::get('route');		
		if (empty($config)) return;
		$routes = Cache::get('wiphp_rule');
		$flip_routes = Cache::get('wiphp_fliprule');
		if (!$routes || !$flip_routes) { //xxxxxxxxxxx
			$routes = $flip_routes = [];
			foreach ($config as $key =>$val) {
				$key = str_replace(array_keys(self::$types), array_values(self::$types), $key);
				$key = trim(strtolower($key), '/');
				$routes[$key] = trim(strtolower($val), '/');
			}
			
			$temp = array_flip($routes);			
			foreach ($temp as $k => $v) {
				if (preg_match_all('/\(.*?\)/i', $v, $res)) {
					$pat = [];
					for ($i=1;$i<=count($res[0]);$i++){
						$pat[] = '/\$\{'.$i.'\}/i';
					}					
					$k = preg_replace($pat, $res[0], $k);				
					$i = 0;
					$v = preg_replace_callback('/\(.*?\)/i',function ($matches) use(&$i) {
						$i ++;
						return '${'.$i.'}';
					}, $v);
						
					$flip_routes[$k] = $v;
				} else {
					$flip_routes[$k] = $v;
				}				
			}			
			Cache::set('wiphp_rule', $routes);
			Cache::set('wiphp_fliprule', $flip_routes);
		}
		self::$rule = $routes;
		self::$ruleFlip = $flip_routes;
		self::$def_controller = Config::get('app.def_controller', 'index'); //默认控制器
		self::$def_method = Config::get('app.def_method', 'index'); ; //默认操作
	}
	public static function parseUrl() {
		$m = self::$def_controller;
		$a = self::$def_method;
		if (!isset($_SERVER['PATH_INFO']) && $_SERVER['QUERY_STRING']) {
			$_GET['m'] = empty($_GET['m']) ? $m : strtolower($_GET['m']);
			$_GET['a'] = empty($_GET['a']) ? $a : strtolower($_GET['a']);
			$m = $_GET['m'];
			$a = $_GET['a'];
			unset($_GET['m'], $_GET['a']);
			$url = $_SERVER['SCRIPT_NAME'].'/'.$m.'/'.$a;
			if (!empty($_GET)) {
				$query = http_build_query($_GET);
				$url .= '/'.str_replace(array('&', '='), '/', $query);
			}
			header('Location:'.$url);
		}
		$pathinfo = isset($_SERVER['PATH_INFO'])? preg_replace('/\/+/', '/', strtolower($_SERVER['PATH_INFO'])) : $m.'/'.$a;
		$pathinfo = str_replace(strrchr($pathinfo, '.'), '',$pathinfo); //去掉后缀		
		//$pathinfo = filter_var($pathinfo, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH);	//过滤处理
		if (!empty(self::$filter) && preg_match(self::$filter, $pathinfo)) {
			$pathinfo = $m.'/'.$a;
		}		
		return trim($pathinfo, '/');
	}
	//生成url
	public static function getUrl($route = '', $args = [], $suffix = '*') {
		$m = self::$def_controller;
		$a = self::$def_method;
		$suffix = ($suffix == '*')? URL_SUFFIX : $suffix;
		if (in_array($route, ['','@','@/','/@'])) $route = '/'; 
		//路由后?id=1参数		
		$temp = [];
		if (strpos($route, '?')) {
			list($route, $temp) = explode('?', $route);			
			parse_str($temp, $temp);		
		}
		//第二参数
		if ($args == '') $args = [];
		if (!empty($args) && !is_array($args)) {
			parse_str($args, $args);
		}
		$args = array_merge($temp, $args);		
		if ($route == '/' && empty($args)) {			
			return __URL__.'/';
		} else if ($route == '/') {
			$route = $m.'/'.$a;
		}
		$prams = '';
		if (!empty($args)) {			
			$prams = '/'.str_replace(['&', '='], '/', http_build_query($args));		
		} 
		$route = trim($route, '/');
		if (substr($route, 0, 1) == '@') {
			$route = trim($route, '@');
			return __URL__.'/'.$route.$prams.$suffix;
		}		
		$route_list = explode('/', $route);
		if (count($route_list) < 2) {
			$route .= '/'.$a; 
		}
		$path = $route.$prams;		
		$url = '';	
		if (!empty(self::$ruleFlip)) {			
			if (isset(self::$ruleFlip[$path])) {
				return __URL__.'/'.self::$ruleFlip[$path].$suffix;				
			}			
			foreach (self::$ruleFlip as $k => $v) {
				if (preg_match('#^'.$k.'$#i', $path, $matches)) {
					if (strpos($v, '$') !== false && strpos($k, '(') !== false) {						
						$v = preg_replace('#^'.$k.'$#i', $v, $path);
					}					
					$url = $v;
					break;
				}
			}
		}		
		
		$path = !empty($url)? $url : $path;
		return __URL__.'/'.$path.$suffix;
	}
}